"""
容器管理服务 - 专职负责Docker容器管理操作
"""

import subprocess
import os
import tempfile
import yaml
import logging
from typing import Dict, Any

from .types import OperationResult, ContainerConfig, ActionType


logger = logging.getLogger(__name__)


class ContainerManagementService:
    """容器管理服务"""
    
    def __init__(self):
        self.logger = logging.getLogger(self.__class__.__name__)
    
    def execute_action(self, action_type: ActionType, container_name: str, 
                      config: ContainerConfig) -> OperationResult:
        """
        根据操作类型执行相应的容器操作
        
        Args:
            action_type: 操作类型
            container_name: 容器名称
            config: 容器配置
            
        Returns:
            OperationResult: 操作结果
        """
        try:
            if action_type == ActionType.NONE:
                return OperationResult(
                    success=True,
                    message="无需操作",
                    details={"action": "none"}
                )
            elif action_type == ActionType.RESTART:
                return self.restart_container(container_name)
            elif action_type == ActionType.CREATE:
                return self.create_container(config)
            elif action_type == ActionType.UPDATE:
                return self.update_container(container_name, config)
            elif action_type == ActionType.REBUILD:
                return self.rebuild_container(container_name, config)
            else:
                return OperationResult(
                    success=False,
                    message=f"未知的操作类型: {action_type}",
                    error=f"Unsupported action type: {action_type}"
                )
                
        except Exception as e:
            self.logger.error(f"容器操作失败 [{action_type}]: {e}")
            return OperationResult(
                success=False,
                message=f"容器操作失败: {str(e)}",
                error=str(e)
            )
    
    def restart_container(self, container_name: str) -> OperationResult:
        """重启现有容器"""
        try:
            self.logger.info(f"重启容器: {container_name}")
            
            # 重启容器
            cmd = ['docker', 'restart', container_name]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
            
            if result.returncode == 0:
                # 验证容器是否成功启动
                health_result = self._verify_container_health(container_name)
                if health_result['healthy']:
                    return OperationResult(
                        success=True,
                        message=f"容器 {container_name} 重启成功",
                        details={"container_name": container_name, "health": health_result}
                    )
                else:
                    return OperationResult(
                        success=False,
                        message=f"容器重启后健康检查失败",
                        error="Container health check failed after restart"
                    )
            else:
                return OperationResult(
                    success=False,
                    message=f"容器重启失败: {result.stderr}",
                    error=result.stderr
                )
                
        except Exception as e:
            self.logger.error(f"重启容器失败: {e}")
            return OperationResult(
                success=False,
                message=f"重启容器失败: {str(e)}",
                error=str(e)
            )
    
    def create_container(self, config: ContainerConfig) -> OperationResult:
        """创建新容器"""
        try:
            self.logger.info(f"创建容器: {config.container_name}")
            
            # 生成docker-compose文件
            compose_content = self._generate_compose_content(config)
            
            # 写入临时compose文件
            with tempfile.NamedTemporaryFile(mode='w', suffix='.yml', delete=False) as f:
                yaml.dump(compose_content, f, default_flow_style=False)
                compose_file_path = f.name
            
            try:
                # 使用docker-compose创建并启动容器
                env = os.environ.copy()
                env.update({
                    'SCHOOL_NAME': config.school_name,
                    'FULL_IMAGE_URL': config.image_url
                })
                
                cmd = ['docker-compose', '-f', compose_file_path, 'up', '-d']
                result = subprocess.run(cmd, capture_output=True, text=True, 
                                      timeout=300, env=env)
                
                if result.returncode == 0:
                    # 验证容器健康状态
                    health_result = self._verify_container_health(config.container_name)
                    return OperationResult(
                        success=True,
                        message=f"容器 {config.container_name} 创建成功",
                        details={
                            "container_name": config.container_name,
                            "image_url": config.image_url,
                            "health": health_result
                        }
                    )
                else:
                    return OperationResult(
                        success=False,
                        message=f"容器创建失败: {result.stderr}",
                        error=result.stderr
                    )
                    
            finally:
                # 清理临时文件
                try:
                    os.unlink(compose_file_path)
                except Exception:
                    pass
                    
        except Exception as e:
            self.logger.error(f"创建容器失败: {e}")
            return OperationResult(
                success=False,
                message=f"创建容器失败: {str(e)}",
                error=str(e)
            )
    
    def update_container(self, container_name: str, config: ContainerConfig) -> OperationResult:
        """更新镜像并重建容器"""
        try:
            self.logger.info(f"更新容器: {container_name}")
            
            # 1. 停止现有容器
            stop_result = self._stop_container(container_name)
            if not stop_result['success']:
                return OperationResult(
                    success=False,
                    message=f"停止容器失败: {stop_result['error']}",
                    error=stop_result['error']
                )
            
            # 2. 拉取新镜像
            pull_result = self._pull_image(config.image_url)
            if not pull_result['success']:
                return OperationResult(
                    success=False,
                    message=f"拉取镜像失败: {pull_result['error']}",
                    error=pull_result['error']
                )
            
            # 3. 创建新容器
            return self.create_container(config)
            
        except Exception as e:
            self.logger.error(f"更新容器失败: {e}")
            return OperationResult(
                success=False,
                message=f"更新容器失败: {str(e)}",
                error=str(e)
            )
    
    def rebuild_container(self, container_name: str, config: ContainerConfig) -> OperationResult:
        """完整重建容器"""
        try:
            self.logger.info(f"重建容器: {container_name}")
            
            # 1. 停止并删除现有容器
            cleanup_result = self._cleanup_container(container_name)
            if not cleanup_result['success']:
                self.logger.warning(f"清理容器时出现问题: {cleanup_result['error']}")
            
            # 2. 拉取镜像
            pull_result = self._pull_image(config.image_url)
            if not pull_result['success']:
                return OperationResult(
                    success=False,
                    message=f"拉取镜像失败: {pull_result['error']}",
                    error=pull_result['error']
                )
            
            # 3. 创建新容器
            return self.create_container(config)
            
        except Exception as e:
            self.logger.error(f"重建容器失败: {e}")
            return OperationResult(
                success=False,
                message=f"重建容器失败: {str(e)}",
                error=str(e)
            )
    
    def _stop_container(self, container_name: str) -> Dict[str, Any]:
        """停止容器"""
        try:
            cmd = ['docker', 'stop', container_name]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
            
            return {
                'success': result.returncode == 0,
                'error': result.stderr if result.returncode != 0 else None
            }
        except Exception as e:
            return {'success': False, 'error': str(e)}
    
    def _cleanup_container(self, container_name: str) -> Dict[str, Any]:
        """停止并删除容器"""
        try:
            # 停止容器
            subprocess.run(['docker', 'stop', container_name], 
                         capture_output=True, timeout=60)
            
            # 删除容器
            cmd = ['docker', 'rm', container_name]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
            
            return {
                'success': result.returncode == 0,
                'error': result.stderr if result.returncode != 0 else None
            }
        except Exception as e:
            return {'success': False, 'error': str(e)}
    
    def _pull_image(self, image_url: str) -> Dict[str, Any]:
        """拉取Docker镜像"""
        try:
            self.logger.info(f"拉取镜像: {image_url}")
            
            cmd = ['docker', 'pull', image_url]
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
            
            return {
                'success': result.returncode == 0,
                'error': result.stderr if result.returncode != 0 else None,
                'output': result.stdout
            }
        except Exception as e:
            return {'success': False, 'error': str(e)}
    
    def _verify_container_health(self, container_name: str) -> Dict[str, Any]:
        """验证容器健康状态"""
        try:
            # 检查容器是否在运行
            cmd = ['docker', 'ps', '--filter', f'name=^{container_name}$', '--format', 'json']
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
            
            if result.returncode == 0 and result.stdout.strip():
                # 容器正在运行，进一步检查健康状态
                cmd = ['docker', 'inspect', container_name, '--format', '{{.State.Health.Status}}']
                health_result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
                
                health_status = health_result.stdout.strip() if health_result.returncode == 0 else 'unknown'
                
                return {
                    'healthy': True,
                    'running': True,
                    'health_status': health_status
                }
            else:
                return {
                    'healthy': False,
                    'running': False,
                    'health_status': 'not_running'
                }
                
        except Exception as e:
            self.logger.error(f"健康检查失败: {e}")
            return {
                'healthy': False,
                'running': False,
                'health_status': 'check_failed',
                'error': str(e)
            }
    
    def _generate_compose_content(self, config: ContainerConfig) -> Dict[str, Any]:
        """生成docker-compose内容"""
        service_config = {
            'image': config.image_url,
            'container_name': config.container_name,
            'restart': 'unless-stopped',
            'environment': config.environment
        }
        
        # 添加端口映射
        if config.ports:
            service_config['ports'] = [
                f"{external}:{internal}" 
                for internal, external in config.ports.items()
            ]
        
        # 添加数据卷映射
        if config.volumes:
            service_config['volumes'] = [
                f"{host}:{container}" 
                for host, container in config.volumes.items()
            ]
        
        # 添加健康检查
        service_config['healthcheck'] = {
            'test': ['CMD', 'curl', '-f', 'http://localhost:8080/health'],
            'interval': '30s',
            'timeout': '10s',
            'retries': 3
        }
        
        return {
            'version': '3.8',
            'services': {
                config.container_name: service_config
            }
        }